function connect(url) {
    return new Promise((resolve, reject) => {
        const ws = new WebSocket(url);
        ws.onopen = () => {
            resolve(ws);
        }
        ws.onerror = (err) => {
            reject(err);
        }
    })
}

var client = connect('ws://localhost:443');

function batchConnect(url) {
    return new Promise((resolve, reject) => {
        let timer = null;
        const ws = new WebSocket(url);
        ws.onopen = () => {
            clearTimeout(timer);
            resolve(ws);
        }
        ws.onerror = (err) => {
            reject(err);
        }
        timer = setTimeout(() => {
            const ws = new WebSocket(url);
            ws.onopen = () => {
                resolve(ws);
            }
            ws.onerror = (err) => {
                reject(err);
            }
            setTimeout(() => {
                const ws = new WebSocket(url);
                ws.onopen = () => {
                    resolve(ws);
                }
                ws.onerror = (err) => {
                    reject(err);
                }
            }, 500 - 200);
        }, 200);
    })
}

function batchConnect(url) {
    return new Promise((resolve, reject) => {

        const wsArr = [];
        function closeOthers(ws) {
            wsArr.filter(i => i != ws).forEach(i => i.close());
        }

        function connect() {
            const ws = new WebSocket(url);
            wsArr.push(ws);
            ws.onopen = () => onSuccess(ws);
            ws.onerror = onError;
        }
        function onError(err) {
            if (!count--) {
                reject(err);
            }
        }
        function onSuccess(ws) {
            timer && clearTimeout(timer);
            closeOthers(ws);
            resolve(ws);
        }

        const delays = [200, 500];
        let count = delays.length;
        let lastDelay = 0;
        let timer = null;
        function retry() {
            connect();
            if (delays.length) {
                const curDelay = delays.shift();
                timer = setTimeout(retry, curDelay - lastDelay);
                lastDelay = curDelay;
            }
        }

        retry();
    })
}


function withRetry(delays, fn) {
    return function (...args) {
        return new Promise((resolve, reject) => {
            function onError(err) {
                if (!count--) {
                    reject(err);
                }
            }
            function onSuccess(...results) {
                timer && clearTimeout(timer);
                resolve(...results);
            }

            let count = delays.length;
            let lastDelay = 0;
            let timer = null;
            function retry() {
                fn(...args).then(onSuccess).catch(onError);
                if (delays.length) {
                    const curDelay = delays.shift();
                    timer = setTimeout(retry, curDelay - lastDelay);
                    lastDelay = curDelay;
                }
            }
            retry();
        })
    }
}


function batchConnect(url) {

    const wsArr = [];
    function closeOthers(ws) {
        wsArr.filter(i => i != ws).forEach(i => i.close());
    }

    function connect() {
        return new Promise((resolve, reject) => {
            const ws = new WebSocket(url);
            wsArr.push(ws);
            ws.onopen = () => resolve(ws);
            ws.onerror = (err) => reject(err);
        });
    }

    const delays = [200, 500];
    const connectWithRetry = withRetry(delays, connect);
    const result = connectWithRetry();
    result.then(closeOthers);
    return result;
}


function batchConnect(url) {

    const wsArr = [];
    function closeOthers(ws) {
        wsArr.filter(i => i != ws).forEach(i => i.close());
    }

    function connect() {
        return new Promise((resolve, reject) => {
            const ws = new WebSocket(url);
            wsArr.push(ws);
            ws.onopen = () => resolve(ws);
            ws.onerror = (err) => reject(err);
        });
    }

    const delays = [200, 500];
    const withLongRetry = curry(withRetry, [1000, 5000, 10 * 1000]);
    const withQuickRetry = curry(withRetry, [100, 200, 500]);
    const connectWithRetry = withQuickRetry(delays, connect);
    const result = connectWithRetry();
    result.then(closeOthers);
    return result;
}


function curry(fn, length = fn.length, ...args) {
    return function (...innerArgs) {
        const totalArgs = args.concat(innerArgs);
        if (totalArgs.length < length) {
            return curry(fn, length, ...totalArgs);
        } else {
            return fn(...totalArgs);
        }
    }
}